package sumsub

import (
	"encoding/json"
	"fmt"
	"strconv"
	"strings"

	"code.bydev.io/cht/customer/kyc_admin_service/internal/pkg/helper"
	kae_dto "code.bydev.io/cht/customer/kyc_admin_service/internal/pkg/kycadminevent/dto"
	"code.bydev.io/cht/customer/kyc_admin_service/internal/pkg/kycprovider/dto"
	"git.bybit.com/svc/go/pkg/bzap"
	"go.uber.org/zap"
)

type ErrorResponse struct {
	Description   string `json:"description"`
	Code          int    `json:"code"`
	Correlationid string `json:"correlationId"`
}

type SumsubApplicantInfo struct {
	ID                string               `json:"id"`
	Createdat         string               `json:"createdAt"`
	Clientid          string               `json:"clientId"`
	Inspectionid      string               `json:"inspectionId"`
	Externaluserid    string               `json:"externalUserId"`
	Info              SumsubInfo           `json:"info"`
	FixInfo           SumsubInfo           `json:"fixedInfo"`
	Email             string               `json:"email"`
	Applicantplatform string               `json:"applicantPlatform"`
	Requirediddocs    SumsubRequiredidDocs `json:"requiredIdDocs"`
	Review            SumsubReview         `json:"review"`
	Lang              string               `json:"lang"`
	Type              string               `json:"type"`
	SourceKey         string               `json:"sourceKey"`
}

type SumsubAddress struct {
	Country          string `json:"country"`
	PostCode         string `json:"postCode"`
	Town             string `json:"town"`
	Street           string `json:"street"`
	SubStreet        string `json:"subStreet"`
	State            string `json:"state"`
	BuildingName     string `json:"buildingName"`
	FlatNumber       string `json:"flatNumber"`
	BuildingNumber   string `json:"buildingNumber"`
	StartDate        string `json:"startDate"`
	EndDate          string `json:"endDate"`
	FormattedAddress string `json:"formattedAddress"`
}

type SumsubIddocs struct {
	Iddoctype   string        `json:"idDocType"`
	Country     string        `json:"country"`
	Firstname   string        `json:"firstName"`
	Firstnameen string        `json:"firstNameEn"`
	Lastname    string        `json:"lastName"`
	Lastnameen  string        `json:"lastNameEn"`
	Validuntil  string        `json:"validUntil"`
	Number      string        `json:"number"`
	Dob         string        `json:"dob"`
	IssuedDate  string        `json:"issuedDate"`
	Address     SumsubAddress `json:"address"`
}

type SumsubInfo struct {
	Firstname    string          `json:"firstName"`
	Firstnameen  string          `json:"firstNameEn"`
	MiddleName   string          `json:"middleName"`
	MiddleNameEn string          `json:"middleNameEn"`
	Lastname     string          `json:"lastName"`
	Lastnameen   string          `json:"lastNameEn"`
	Dob          string          `json:"dob"`
	Country      string          `json:"country"`
	Gender       string          `json:"gender"`
	Nationality  string          `json:"nationality"`
	Iddocs       []*SumsubIddocs `json:"idDocs"`
	Addresses    []SumsubAddress `json:"addresses"`
	Tin          string          `json:"tin"`
}

type SumsubDocsets struct {
	Iddocsettype string   `json:"idDocSetType"`
	Types        []string `json:"types"`
}

type SumsubRequiredidDocs struct {
	Docsets []SumsubDocsets `json:"docSets"`
}

type SumsubReview struct {
	Elapsedsincependingms int          `json:"elapsedSincePendingMs"`
	Elapsedsincequeuedms  int          `json:"elapsedSinceQueuedMs"`
	Reprocessing          bool         `json:"reprocessing"`
	Levelname             string       `json:"levelName"`
	Createdate            string       `json:"createDate"`
	Reviewdate            string       `json:"reviewDate"`
	Startdate             string       `json:"startDate"`
	Reviewresult          Reviewresult `json:"reviewResult"`
	Reviewstatus          string       `json:"reviewStatus"`
}

func (a *SumsubApplicantInfo) GetApplicantPlatform() string {
	return a.Applicantplatform
}

// GetFirstName firstname
func (a *SumsubApplicantInfo) GetFirstName() string {
	if a.IsBVN() {
		if a.Info.Firstname != "" {
			return a.Info.Firstname
		} else {
			return a.FixInfo.Firstname
		}
	} else {
		return a.Info.Firstname
	}
}

func (a *SumsubApplicantInfo) GetMiddleName() string {
	if a.IsBVN() {
		if a.Info.Firstname != "" {
			return a.Info.MiddleName
		} else {
			return a.FixInfo.MiddleName
		}
	} else {
		return a.Info.MiddleName
	}
}

// GetLastName last name
func (a *SumsubApplicantInfo) GetLastName() string {
	if a.IsBVN() {
		if a.Info.Lastname != "" {
			return a.Info.Lastname
		} else {
			return a.FixInfo.Lastname
		}
	} else {
		return a.Info.Lastname
	}
}

// GetDOB date of birthday
func (a *SumsubApplicantInfo) GetDOB() string {
	return a.Info.Dob
}

func (a *SumsubApplicantInfo) GetIssuedDate(docType string) string {
	dl := len(a.Info.Iddocs)
	if dl > 0 {
		for _, doc := range a.Info.Iddocs {
			if doc.IssuedDate != "" && docType == doc.Iddoctype {
				return doc.IssuedDate
			}
		}
	}

	return ""
}

// GetLevelName level name string
func (a *SumsubApplicantInfo) GetLevelName() string {
	return a.Review.Levelname
}

// IsBVN Is BVN
func (a *SumsubApplicantInfo) IsBVN() bool {
	lvlName := a.GetLevelName()
	switch lvlName {
	case dto.Level1BVN.String(), dto.Level2BVN.String(), dto.Level1SecondaryBVN.String():
		return true
	}

	return false
}

// IsSecondary Is secondary
func (a *SumsubApplicantInfo) IsSecondary() bool {
	return dto.LvlNameIsSecondary(a.GetLevelName())
}

// IsSupplement Is supplement
func (a *SumsubApplicantInfo) IsSupplement() bool {
	return dto.LvlNameIsSupplement(a.GetLevelName())
}

// GetCountry return country from info
func (a *SumsubApplicantInfo) GetCountry() string {
	if a.IsBVN() {
		return a.FixInfo.Country
	} else {
		return a.Info.Country
	}
}

func (a *SumsubApplicantInfo) getFilteredAddress(countryCode string) SumsubAddress {
	var (
		l    int
		adrs []SumsubAddress
	)
	if a.GetLevelName() == dto.Level1BVN.String() {
		l = len(a.FixInfo.Addresses)
		adrs = a.FixInfo.Addresses
	} else {
		l = len(a.Info.Addresses)
		adrs = a.Info.Addresses
	}
	if l > 0 {
		if countryCode != "" {
			for i := range adrs {
				adr := &adrs[i]
				item := SumsubAddress{
					Country:          adr.Country,
					PostCode:         adr.PostCode,
					Town:             adr.Town,
					Street:           adr.Street,
					SubStreet:        adr.SubStreet,
					State:            adr.State,
					BuildingName:     adr.BuildingName,
					FlatNumber:       adr.FlatNumber,
					BuildingNumber:   adr.BuildingNumber,
					StartDate:        adr.StartDate,
					EndDate:          adr.EndDate,
					FormattedAddress: adr.FormattedAddress,
				}
				if item.Country == countryCode {
					return item
				}
			}
		}
		return adrs[l-1]
	}
	return SumsubAddress{}
}

// GetAddressCountry return address country
func (a *SumsubApplicantInfo) GetAddressCountry() string {
	return a.getFilteredAddress(a.GetCountry()).Country
}

// GetAddressPostCode return address postal code
func (a *SumsubApplicantInfo) GetAddressPostCode() string {
	return a.getFilteredAddress(a.GetCountry()).PostCode
}

// GetAddressTown return address town
func (a *SumsubApplicantInfo) GetAddressTown() string {
	return a.getFilteredAddress(a.GetCountry()).Town
}

// GetAddressStreet return address street
func (a *SumsubApplicantInfo) GetAddressStreet() string {
	return a.getFilteredAddress(a.GetCountry()).Street
}

// GetAddressSubStreet return address sub-street
func (a *SumsubApplicantInfo) GetAddressSubStreet() string {
	return a.getFilteredAddress(a.GetCountry()).SubStreet
}

// GetAddressState return address state
func (a *SumsubApplicantInfo) GetAddressState() string {
	return a.getFilteredAddress(a.GetCountry()).State
}

// GetAddressBuildingName return address building name
func (a *SumsubApplicantInfo) GetAddressBuildingName() string {
	return a.getFilteredAddress(a.GetCountry()).BuildingName
}

// GetAddressBuildingNumber return address building number
func (a *SumsubApplicantInfo) GetAddressBuildingNumber() string {
	return a.getFilteredAddress(a.GetCountry()).BuildingNumber
}

func (a *SumsubApplicantInfo) GetFormattedAddress() string {
	fmtAdr := ""
	if len(a.Info.Addresses) > 0 {
		for i := range a.Info.Addresses {
			if a.Info.Addresses[i].FormattedAddress != "" {
				fmtAdr = a.Info.Addresses[i].FormattedAddress
			}
		}
	}
	return fmtAdr
}

func (a *SumsubApplicantInfo) GetFullAddress() string {
	fmtAdr := a.GetFormattedAddress()
	if fmtAdr == "" {
		countryCode := a.GetAddressCountry()
		fullCountry := fmt.Sprintf("%s ", countryCode)
		countryName := helper.CountryNameAlpha3(countryCode)
		if countryName.EnName != "" {
			fullCountry = fmt.Sprintf("%s ", countryName.EnName)
		}
		fmtAdr = strings.Trim(fmt.Sprintf("%s %s %s %s %s",
			fullCountry,
			a.GetAddressState(),
			a.GetAddressTown(),
			a.GetAddressStreet(),
			a.GetAddressSubStreet(),
		), " ")
	}
	return fmtAdr
}

// GetIdentifies return identify info of user
func (a *SumsubApplicantInfo) GetIdentifies() []*dto.Identify {
	r := make([]*dto.Identify, 0)
	for _, doc := range a.Info.Iddocs {
		id := &dto.Identify{
			Firstname:  doc.Firstname,
			Lastname:   doc.Lastname,
			Country:    doc.Country,
			Number:     doc.Number,
			Validuntil: doc.Validuntil,
			Dob:        doc.Dob,
			Type:       GetDocType(doc.Iddoctype),
			IssuedDate: doc.IssuedDate,
			RawType:    doc.Iddoctype,
		}
		r = append(r, id)
	}
	return r
}

// GetLevel related to sumsub-dashboard config
func (a *SumsubApplicantInfo) GetLevel() dto.KYCLevel {
	switch a.Review.Levelname {
	case dto.Level1.String():
		return dto.Level1
	case dto.Level2.String():
		return dto.Level2
	default:
		return dto.Level1
	}
}

// IsIndividual individual or company
func (a *SumsubApplicantInfo) GetKYCType() dto.KYCType {
	switch a.Type {
	case "individual":
		return dto.KYCTypeIndividual
	case "company":
		return dto.KYCTypeCompany
	default:
		return dto.KYCTypeIndividual
	}
}

func (a *SumsubApplicantInfo) GetRejectReasons() []string {
	return a.Review.Reviewresult.Rejectlabels
}

func (a *SumsubApplicantInfo) GetRejectReasonsStr() string {
	if len(a.GetRejectReasons()) >= 1 {
		return strings.Join(a.GetRejectReasons(), ",")
	}
	return ""
}

// GetReviewResult review result
func (a *SumsubApplicantInfo) GetReviewResult() dto.ReviewResult {
	switch a.Review.Reviewresult.Reviewanswer {
	case "GREEN":
		return dto.ReviewResultPass
	case "RED":
		return dto.ReviewResultReject
	default:
		return dto.ReviewResultUnknown
	}
}

// FixDocTypeNoLv1Info 处理旧数据时，Lv2 用户没有 Lv1 状态数据时，从 applicant 补齐
func (a *SumsubApplicantInfo) FixDocTypeNoLv1Info(level int, firstPoi *dto.Identify, finalDecision int) string {
	if dto.KYCLevel(level) == dto.Level1 && (a.Review.Levelname == dto.Level2.String() || a.Review.Levelname == dto.Level2Secondary.String()) && finalDecision == 1 {
		for _, doc := range a.Info.Iddocs {
			if doc.Iddoctype != "" && firstPoi != nil && GetDocType(doc.Iddoctype).String() == firstPoi.Type.String() {
				return doc.Iddoctype
			}
		}
	}
	return ""
}

func (a *SumsubApplicantInfo) GetReviewResultWithLvl(logger *zap.Logger, applicantStatus *StatusResponse, level int) (dto.ReviewResult, string) {
	var (
		labels []string
		rvwRet dto.ReviewResult
	)
	lvl := dto.KYCLevel(level)
	rvwRet = getReviewResult(a.Review.Reviewresult.Reviewanswer)
	lvlName := a.Review.Levelname
	if lvlName == lvl.String() {
		labels = a.Review.Reviewresult.Rejectlabels
	} else {
		switch lvl {
		case dto.Level1:
			rrSelfie := getReviewResult(applicantStatus.Selfie.ReviewResult.ReviewAnswer)
			// BVN 类型没有 IDENTITY，补偿数据时需要特殊处理
			if lvlName == dto.Level1BVN.String() || lvlName == dto.Level2BVN.String() || lvlName == dto.Level1SecondaryBVN.String() ||
				applicantStatus.Identity.ReviewResult.ReviewAnswer == "" {
				if rrSelfie == dto.ReviewResultPass {
					rvwRet = dto.ReviewResultPass
				} else {
					rvwRet = dto.ReviewResultReject
					labels = getRejectLabels(logger, applicantStatus.Selfie.ImageReviewResults, labels)
					if len(labels) >= 1 {
						return rvwRet, strings.Join(labels, ",")
					}
				}
				return rvwRet, ""
			}
			rrIdentify := getReviewResult(applicantStatus.Identity.ReviewResult.ReviewAnswer)
			if rrSelfie == dto.ReviewResultPass && rrIdentify == dto.ReviewResultPass {
				rvwRet = dto.ReviewResultPass
			} else {
				// 如果是 Lv2 且 Lv2 通过，此时 Lv1 即使没有数据也认为通过
				if lvlName == dto.Level2.String() && rvwRet == dto.ReviewResultPass {
					rvwRet = dto.ReviewResultPass
				} else {
					rvwRet = dto.ReviewResultReject
					labels = getRejectLabels(logger, applicantStatus.Identity.ImageReviewResults, labels)
					labels = getRejectLabels(logger, applicantStatus.Selfie.ImageReviewResults, labels)
				}
			}
		case dto.Level2:
			rvwRet = getReviewResult(applicantStatus.ProofOfResidence.ReviewResult.ReviewAnswer)
			for _, ret := range applicantStatus.ProofOfResidence.ImageReviewResults {
				rvuRet := new(ImageReviewResult)
				data, err := json.Marshal(ret)
				if err != nil {
					bzap.LogError(logger.With(zap.Any("applicantStatus", applicantStatus), zap.Any("ret", ret)), "ProofOfResidence Marshal", err)
					continue
				}
				err = json.Unmarshal(data, &rvuRet)
				if err != nil {
					bzap.LogError(logger.With(zap.Any("applicantStatus", applicantStatus), zap.Any("ret", ret)), "ProofOfResidence Unmarshal", err)
					continue
				}
				labels = append(labels, rvuRet.RejectLabels...)
			}
		}
	}
	if len(labels) >= 1 {
		return rvwRet, strings.Join(labels, ",")
	}
	return rvwRet, ""
}

func getRejectLabels(logger *zap.Logger, imgRvuRets map[string]interface{}, labels []string) []string {
	for _, ret := range imgRvuRets {
		rvuRet := new(ImageReviewResult)
		data, err := json.Marshal(ret)
		if err != nil {
			bzap.LogError(logger.With(zap.Any("ret", ret)), "getRejectLabels Marshal", err)
			continue
		}
		err = json.Unmarshal(data, &rvuRet)
		if err != nil {
			bzap.LogError(logger.With(zap.Any("ret", ret)), "getRejectLabels Unmarshal", err)
			continue
		}
		labels = append(labels, rvuRet.RejectLabels...)
	}

	return labels
}

func getReviewResult(reviewAnswer string) dto.ReviewResult {
	switch reviewAnswer {
	case "GREEN":
		return dto.ReviewResultPass
	case "RED":
		return dto.ReviewResultReject
	default:
		return dto.ReviewResultUnknown
	}
}

// GetFilteredIdentity 获取 country 和 name
func (a *SumsubApplicantInfo) GetFilteredIdentity(applicantStatus *StatusResponse, ntf *kae_dto.KYCEventNotify, firstPoi *dto.Identify) *dto.Identify {
	identities := a.GetIdentifies()
	if len(identities) > 0 {
		// 多个证件的情况下，找出唯一匹配的证件
		var (
			actualIdentity Identity
			identifyFound  *dto.Identify
			filterStatus   bool
		)

		if ntf.IsFromMigrate() && firstPoi != nil {
			actualIdentity = Identity{
				Country:   firstPoi.Country,
				Iddoctype: firstPoi.Type.ToSourceType(),
			}
		} else {
			if a.IsSecondary() && !a.IsSupplement() { // 第二证件
				actualIdentity = applicantStatus.SecondaryIdentity
			} else {
				actualIdentity = applicantStatus.Identity
			}
		}

		// 区分 status 接口有无返回 Identity
		if GetDocType(actualIdentity.Iddoctype) == "unknown" && actualIdentity.Country == "" {
			filterStatus = false
		} else {
			filterStatus = true
		}
		for _, identify := range identities {
			if identify.Type != dto.DocumentTypeID && identify.Type != dto.DocumentTypePassport &&
				identify.Type != dto.DocumentTypeDriver && identify.Type != dto.DocumentTypeResidence {
				continue
			}
			if filterStatus {
				if identify.Type == GetDocType(actualIdentity.Iddoctype) && identify.Country == actualIdentity.Country {
					identifyFound = identify
				}
			} else {
				// 再作姓名校验
				if a.Info.Firstname == identify.Firstname && a.Info.Lastname == identify.Lastname {
					// 取最后一个符合条件的，所以不加break
					identifyFound = identify
				}
			}
		}
		if identifyFound != nil {
			return identifyFound
		}
	}
	return nil
}

// GetFilteredIdentity4Lv2 Lv2 获取 country 和 name
// DONE: POA 解耦需要修改
func (a *SumsubApplicantInfo) GetFilteredIdentity4Lv2(status *StatusResponse) *dto.Identify {
	identities := a.GetIdentifies()
	if len(identities) > 0 {
		// 多个证件的情况下，找出唯一匹配的证件
		var (
			identifyFound           *dto.Identify
			profCountry, pofRawType string
		)
		if a.IsSecondary() && !a.IsSupplement() { // 旧的第二证明
			profCountry = status.SecondaryProofOfResidence.Country
			pofRawType = status.SecondaryProofOfResidence.Iddoctype
		} else {
			profCountry = status.ProofOfResidence.Country
			pofRawType = status.ProofOfResidence.Iddoctype
		}
		for _, identify := range identities {
			// 由于第一证明和第二证明都是证明类型，需要用原始类型判断
			if identify.RawType == pofRawType {
				if identify.Country == "" || profCountry == "" {
					identifyFound = identify
				} else if identify.Country == profCountry {
					identifyFound = identify
				}
			}
		}
		if identifyFound != nil {
			return identifyFound
		}
	}
	return nil
}

func (a *SumsubApplicantInfo) Nationality() string {
	if a.IsBVN() {
		return a.FixInfo.Nationality
	}
	return a.Info.Nationality
}

// GetIDCard return type of id_card number
func (a *SumsubApplicantInfo) GetIDCard() string {
	for _, doc := range a.Info.Iddocs {
		if doc.Iddoctype == "ID_CARD" {
			return doc.Number
		}
	}

	return ""
}

func (a *SumsubApplicantInfo) GetGender() dto.Gender {
	switch a.Info.Gender {
	case "M":
		return dto.GenderMale
	case "F":
		return dto.GenderFemale
	default:
		return dto.GenderUnknown
	}
}

// GetState state of workflow
func (a *SumsubApplicantInfo) GetState() dto.ReviewState {
	switch a.Review.Reviewstatus {
	case "init":
		return dto.StateInit
	case "completed":
		return dto.StateComplete
	case "pending":
		return dto.StatePending
	default:
		return dto.StatePending
	}
}

// GetID applicant id in sumsub
func (a *SumsubApplicantInfo) GetID() string {
	return a.ID
}

// GetExternalID hashid of internal user id
func (a *SumsubApplicantInfo) GetExternalID() string {
	return a.Externaluserid
}

// GetInspectionID inspection id in sumsub
func (a *SumsubApplicantInfo) GetInspectionID() string {
	return a.Inspectionid
}

// StatusResponse document review status
type StatusResponse struct {
	ApplicantData struct {
		Country      string `json:"country"`
		Iddoctype    string `json:"idDocType"`
		ReviewResult struct {
			ReviewAnswer string `json:"reviewAnswer"`
		} `json:"reviewResult"`
	} `json:"APPLICANT_DATA"`
	Identity                  Identity `json:"IDENTITY"`            // 第一证件
	ProofOfResidence          Identity `json:"PROOF_OF_RESIDENCE"`  // 第一证明
	SecondaryIdentity         Identity `json:"IDENTITY2"`           // 第二证件
	SecondaryProofOfResidence Identity `json:"PROOF_OF_RESIDENCE2"` // 第二证明
	Selfie                    Selfie   `json:"SELFIE"`              // 自拍
}

type ImageReviewResult struct {
	ModerationComment string   `json:"moderationComment"`
	ClientComment     string   `json:"clientComment"`
	ReviewAnswer      string   `json:"reviewAnswer"`
	RejectLabels      []string `json:"rejectLabels"`
	ReviewRejectType  string   `json:"reviewRejectType"`
	ButtonIds         []string `json:"buttonIds"`
}

type Identity struct {
	Country      string `json:"country"`
	Iddoctype    string `json:"idDocType"`
	Imageids     []int  `json:"imageIds"`
	ReviewResult struct {
		ModerationComment string `json:"moderationComment"`
		ReviewAnswer      string `json:"reviewAnswer"`
	} `json:"reviewResult"`
	ImageReviewResults map[string]interface{} `json:"imageReviewResults"`
}

type Selfie struct {
	ReviewResult struct {
		ReviewAnswer string `json:"reviewAnswer"`
	} `json:"reviewResult"`
	Country            string                 `json:"country"`
	IDDocType          string                 `json:"idDocType"`
	ImageIds           []int                  `json:"imageIds"`
	ImageReviewResults map[string]interface{} `json:"imageReviewResults"`
	Forbidden          bool                   `json:"forbidden"`
	DoubleSided        bool                   `json:"doubleSided"`
	StepStatuses       interface{}            `json:"stepStatuses"`
	RejectLabels       []string               `json:"rejectLabels"`
}
type ReviewAnswer struct {
	ReviewAnswer string   `json:"reviewAnswer"`
	RejectLabels []string `json:"rejectLabels"`
}

type NotifyResponse struct {
	Applicantid    string       `json:"applicantId"`
	Inspectionid   string       `json:"inspectionId"`
	Correlationid  string       `json:"correlationId"`
	Externaluserid string       `json:"externalUserId"`
	Type           string       `json:"type"` // applicantReviewed, applicantCreated,etc
	Reviewresult   Reviewresult `json:"reviewResult"`
	// indicates that the verification process has been completed
	// NOTE: it does not mean that the applicant was approved,
	// it just means that an applicant was processed
	Reviewstatus string           `json:"reviewStatus"`
	Createdat    string           `json:"createdAt"`
	FinalResult  dto.ReviewResult `json:"finalResult"`
}

type ResetApplicantResponse struct {
	Ok int `json:"ok"`
}

func (r *ResetApplicantResponse) GetResetApplicantIsOk() bool {
	return r.Ok == 1
}

func (n *NotifyResponse) Reset() {
	*n = NotifyResponse{}
}

type Reviewresult struct {
	// final answer that should be highly trusted (only 'RED' and 'GREEN' are currently supported)
	Reviewanswer string `json:"reviewAnswer"`
	// a machine-readable constant that describes the problems in case of verification failure
	Rejectlabels     []string `json:"rejectLabels"`
	Reviewrejecttype string   `json:"reviewRejectType"` // FINAL, RETRY
}

// GetReviewResult review result
func (n *NotifyResponse) GetReviewResult() dto.ReviewResult {
	switch n.Reviewresult.Reviewanswer {
	case "GREEN":
		return dto.ReviewResultPass
	case "RED":
		return dto.ReviewResultReject
	default:
		return dto.ReviewResultUnknown
	}
}

func (n *NotifyResponse) GetInspectionID() string {
	return n.Inspectionid
}

func (n *NotifyResponse) CanRetry() bool {
	return n.Reviewresult.Reviewrejecttype != "FINAL"
}

func (n *NotifyResponse) GetExternalUserID() string {
	return n.Externaluserid
}

func (n *NotifyResponse) GetApplicantState() dto.ApplicantState {
	switch n.Type {
	case "applicantCreated":
		return dto.ApplicantCreated
	case "applicantPending":
		return dto.ApplicantPending
	case "applicantReviewed":
		return dto.ApplicantReviewed
	case "applicantReset":
		return dto.ApplicantReset
	default:
		return dto.ApplicantPending
	}
}

func (n *NotifyResponse) GetReviewState() dto.ReviewState {
	switch n.Reviewstatus {
	case "init":
		return dto.StateInit
	case "pending":
		return dto.StatePending
	case "completed":
		return dto.StateComplete
	default:
		return dto.StatePending
	}
}

func (n *NotifyResponse) GetProvider() dto.KYCProvider {
	return dto.ProviderSumSub
}

func (n *NotifyResponse) GetRejectReasons() []string {
	return n.Reviewresult.Rejectlabels
}

func (n *NotifyResponse) GetApplicantID() string {
	return n.Applicantid
}

func GetDocType(doctype string) dto.DocumentType {
	switch doctype {
	case "ID_CARD", "ID_CARD2":
		return dto.DocumentTypeID
	case "PASSPORT", "PASSPORT2":
		return dto.DocumentTypePassport
	case "DRIVERS", "DRIVERS2":
		return dto.DocumentTypeDriver
	case "SELFIE":
		return dto.DocumentTypeSelfie
	case "BANK_CARD":
		return dto.DocumentTypeBank
	case "RESIDENCE_PERMIT", "RESIDENCE_PERMIT2":
		return dto.DocumentTypeResidence
	case "UTILITY_BILL", "UTILITY_BILL2":
		return dto.DocumentTypeBill
	case "BVN", "BVN2":
		return dto.DocumentTypeBVN
	default:
		return dto.DocumentTypeUnknown
	}
}

func (a *SumsubApplicantInfo) Reviewdate() string {
	return a.Review.Reviewdate
}

func (a *SumsubApplicantInfo) IsValidity() string {
	for _, lbl := range a.GetRejectReasons() {
		switch dto.SumsubValidity(lbl) {
		case dto.SumsubValiditySelfieMismatch, dto.SumsubValidityBadSelfie, dto.SumsubValidityBadVideoSelfie, dto.SumsubValidityBadFaceMatch:
			return "false"
		}
	}
	if a.GetReviewResult().IsPassed() {
		return "true"
	}
	return ""
}

func (a *SumsubApplicantInfo) GetSimilarity() string {
	for _, lbl := range a.GetRejectReasons() {
		if dto.SumsubSimilarity(lbl) == dto.SumsubSimilarityFraudulent {
			return "NOT MATCH"
		}
	}
	if a.GetReviewResult().IsPassed() {
		return "MATCH"
	}

	return ""
}

func (s *StatusResponse) GetDocType(isSecondary, isSupplement bool) string {
	if isSecondary && !isSupplement {
		return s.SecondaryIdentity.Iddoctype
	} else {
		return s.Identity.Iddoctype
	}
}

// GetDocType4Lvl2 获取证件/证明类型（支持 POA 解耦）
func (s *StatusResponse) GetDocType4Lvl2(isSecondary, isSupplement bool) string {
	if isSecondary && !isSupplement {
		return s.SecondaryProofOfResidence.Iddoctype
	} else {
		return s.ProofOfResidence.Iddoctype
	}
}

func (s *StatusResponse) GetCountry4Lvl2() string {
	// 第1优先-》第二证明
	if s.SecondaryProofOfResidence.Country != "" {
		return s.SecondaryProofOfResidence.Country
	}
	// 第2优先-》第一证明
	if s.ProofOfResidence.Country != "" {
		return s.ProofOfResidence.Country
	}
	// 第3优先-》第二证件
	if s.SecondaryIdentity.Country != "" {
		return s.SecondaryIdentity.Country
	}
	// 第4优先-》第一证件
	if s.Identity.Country != "" {
		return s.Identity.Country
	}

	return ""
}

// Deprecated: GetCountry4Lvl2 用于旧数据补齐，新数据不再使用
func (s *StatusResponse) GetFrontBackFaceImage(isSecondary bool) (string, string, string) {
	var (
		ft, bk, fc string
		idImgs     []int
	)
	if isSecondary {
		idImgs = s.SecondaryIdentity.Imageids
	} else {
		idImgs = s.Identity.Imageids
	}
	if len(idImgs) > 0 {
		for k, v := range idImgs {
			if k == 0 {
				ft = strconv.Itoa(v)
			} else {
				bk = strconv.Itoa(v)
			}
		}
	}

	sfImgs := s.Selfie.ImageIds
	if len(sfImgs) > 0 {
		fc = strconv.Itoa(sfImgs[0])
	}

	return ft, bk, fc
}

func (s *StatusResponse) GetFrontBackFaceImage4Lvl2(isSecondary bool) (string, string, string) {
	var (
		ft, bk, fc string
		idImgs     []int
	)
	if isSecondary {
		idImgs = s.SecondaryProofOfResidence.Imageids
	} else {
		idImgs = s.ProofOfResidence.Imageids
	}
	if len(idImgs) > 0 {
		for k, v := range idImgs {
			if k == 0 {
				ft = strconv.Itoa(v)
			} else {
				bk = strconv.Itoa(v)
			}
		}
	}

	sfImgs := s.Selfie.ImageIds
	if len(sfImgs) > 0 {
		fc = strconv.Itoa(sfImgs[0])
	}

	return ft, bk, fc
}

func (s *StatusResponse) GetIdentityImageIds(isSecondary, isSupplement bool) []int {
	if isSecondary && !isSupplement {
		return s.SecondaryIdentity.Imageids
	} else {
		return s.Identity.Imageids
	}
}

// GetProofOfResidenceImageIds 获取证明图片资源 ID（支持 POA 解耦）
func (s *StatusResponse) GetProofOfResidenceImageIds(isSecondary, isSupplement bool) []int {
	if isSecondary && !isSupplement {
		return s.SecondaryProofOfResidence.Imageids
	} else {
		return s.ProofOfResidence.Imageids
	}
}
